﻿/**
 *	(C) 2014 Yuanjj
 *
 *	define thread base class
 *
 *	histroy
 * 		2014-08-07	yuanjj	- create the file
 */

#include "base_thread.h"
#include "errorcode.h"
#include "routine/global.h"
#include "routine/protocal/protocal.h"

/****************************************************
 * vbase_thread
 ****************************************************/
vbase_thread::vbase_thread()
{
    m_stop 		= true;
}

vbase_thread::~vbase_thread()
{

}

/**
 *	start thread
 *
 * 	return
 * 		==	PEM_OK		successful
 * 		!=	PEM_OK		errorcode
 */
pem_error_t vbase_thread::start_thread()
{
    m_stop = false;
    start();

    if ( isRunning() )
        return PEM_OK;
    else
        return BUILD_ERRORCODE( 0, PEM_THREAD_CREATE );
}

/**
 *	stop thread
 */
pem_void_t vbase_thread::stop_thread()
{
    m_stop = true;
    exit();
    if ( !wait( 5000 ) )
        terminate();
}

/****************************************************
 * base_thread
 ****************************************************/
extern cls_bridge* 	g_viewer;
base_thread::base_thread()
{
}

base_thread::~base_thread()
{
}

/**
 *	thread fun for dealing protocal
 */
pem_void_t base_thread::run()
{
    pem_s8_t		buf[8192];
    pem_u32_t		size;
    pem_error_t		res;

    QObject::connect( this, SIGNAL(call_js( QString )), g_viewer, SLOT(on_call_js( QString )) );

    while( !m_stop )
    {
        res = recv_protocal( buf, sizeof(buf), size );
        if ( PEM_OK != res && PEM_QUEUE_EMPTY == GET_PEM_ERROR(res) )
        {
            msleep( 100 );
            continue;
        }

        deal_protocal( buf, size );
    }
}

/**
 *	recv a protocal from tunnel
 *
 *	@pdata			[out] the data buffer
 * 	@size			[in] the size of data buffer
 * 	@rcvsize		[out] the data size that load into the buffer
 *
 *	return
 * 		==	PEM_OK		successful
 * 		!=	PEM_OK		errorcode
 */
pem_error_t base_thread::recv_protocal( pem_s8_t* pdata, pem_u32_t size, pem_u32_t& rcvsize )
{
    pem_error_t		res;
    head_in&		head = *(head_in*)pdata;

    if ( sizeof(head_in) > size )
    {
        g_log.write( LOG_ERR, "base recv head", "buf size(%u) lower than head size(%u)[tunnel = %d]", size, sizeof(head_in), m_tunnel );
        return BUILD_ERRORCODE( 0, PEM_TUNNEL_BUFSIZE );
    }

    res = g_tunnel.getdata( m_tunnel, pdata, sizeof(head_in) );
    if ( PEM_OK != res )
    {
        if ( PEM_QUEUE_EMPTY != GET_PEM_ERROR( res ) )
            g_log.write( LOG_ERR, "base recv head", "recv head failed[error = 0x%x][tunnel = %d]", res, m_tunnel );
        return res;
    }

    if ( size - sizeof(head_in) < head.size )
    {
        g_log.write( LOG_ERR, "base recv body", "buf size(%u) lower than body size(%u)[tunnel = %d]", size - sizeof(head_in), head.size, m_tunnel );
        return BUILD_ERRORCODE( 0, PEM_TUNNEL_BUFSIZE );
    }

    if ( 0 != head.size )
    {
        res = g_tunnel.getdata( m_tunnel, (pem_s8_t*)(&head + 1), head.size );
        if ( PEM_OK != res )
        {
            g_log.write( LOG_ERR, "base recv body", "recv body failed[error = 0x%x][tunnel = %d]", res, m_tunnel );
            return res;
        }
    }

    rcvsize = sizeof(head_in) + head.size;

    return 	PEM_OK;
}

/**
 *	deal protocal recv from the tunnel
 *
 * 	@pdata			[in] the protocal buffer
 * 	@size			[in] the buffer size
 *
 * 	return
 * 		==	PEM_OK		protocal is good
 * 		!=	PEM_OK		errorcode
 */
pem_error_t base_thread::deal_protocal( pem_s8_t* pdata, pem_u32_t size )
{
    head_in&		head = *(head_in*)pdata;

    if ( sizeof(head_in) > size || head.size + sizeof(head_in) > size )
    {
        g_log.write( LOG_WARN, "protocal(tunnel=%d)", "protocal size(%d) is not correct", m_tunnel, size );
        return BUILD_ERRORCODE( 0, PEM_PROTOCAL_SIZE);
    }

    if ( HEAD_MAGIC != head.magic )
    {
        g_log.write( LOG_WARN, "protocal(tunnel=%d)", "head magic(0x%x) is not correct", m_tunnel, head.magic );
        return BUILD_ERRORCODE( 0, PEM_PROTOCAL_MAGIC );
    }

    if ( head.main != m_main )
    {
        g_log.write( LOG_WARN, "protocal(tunnel=%d)", "protocal main(%d) is not correct", m_tunnel, head.main );
        return BUILD_ERRORCODE( 0, PEM_PROTOCAL_MAIN );
    }

    return	PEM_OK;
}
